package com.micro.ai.files.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.micro.ai.commons.exception.BusinessException;
import com.micro.ai.files.entity.FileFolder;
import com.micro.ai.files.mapper.FileFolderMapper;
import com.micro.ai.files.service.FileFolderService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;

import java.time.LocalDateTime;
import java.util.List;
import java.util.stream.Collectors;

/**
 * 文件夹服务实现
 * 
 * @author micro-ai
 * @since 0.0.1
 */
@Slf4j
@Service
public class FileFolderServiceImpl extends ServiceImpl<FileFolderMapper, FileFolder> implements FileFolderService {

    @Override
    @Transactional(rollbackFor = Exception.class)
    public FileFolder create(FileFolder folder) {
        if (folder == null) {
            throw new BusinessException("F0000", "文件夹信息不能为空");
        }
        
        if (!StringUtils.hasText(folder.getTenantId())) {
            throw new BusinessException("F0000", "租户ID不能为空");
        }
        
        if (!StringUtils.hasText(folder.getName())) {
            throw new BusinessException("F0000", "文件夹名称不能为空");
        }
        
        // 检查同级目录下是否有同名文件夹
        LambdaQueryWrapper<FileFolder> query = new LambdaQueryWrapper<>();
        query.eq(FileFolder::getTenantId, folder.getTenantId())
             .eq(FileFolder::getParentId, folder.getParentId())
             .eq(FileFolder::getName, folder.getName())
             .isNull(FileFolder::getDeletedAt);
        
        FileFolder existing = this.getOne(query);
        if (existing != null) {
            throw new BusinessException("F0001", "同级目录下已存在同名文件夹: " + folder.getName());
        }
        
        // 生成完整路径
        String fullPath = generateFullPath(folder.getTenantId(), folder.getParentId(), folder.getName());
        folder.setFullPath(fullPath);
        
        if (folder.getFolderType() == null) {
            folder.setFolderType("normal");
        }
        
        LocalDateTime now = LocalDateTime.now();
        folder.setCreatedAt(now);
        folder.setUpdatedAt(now);
        
        boolean success = this.save(folder);
        if (!success) {
            throw new BusinessException("F0003", "创建文件夹失败");
        }
        
        log.info("创建文件夹成功: folderId={}, name={}, fullPath={}", 
                folder.getId(), folder.getName(), folder.getFullPath());
        return folder;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public FileFolder update(String id, FileFolder folder) {
        if (!StringUtils.hasText(id)) {
            throw new BusinessException("F0000", "文件夹ID不能为空");
        }
        if (folder == null) {
            throw new BusinessException("F0000", "文件夹信息不能为空");
        }
        
        FileFolder existing = this.getById(id);
        if (existing == null || existing.getDeletedAt() != null) {
            throw new BusinessException("F0002", "文件夹不存在: " + id);
        }
        
        folder.setId(id);
        
        boolean success = this.updateById(folder);
        if (!success) {
            throw new BusinessException("F0003", "更新文件夹失败");
        }
        
        log.info("更新文件夹成功: folderId={}", id);
        return folder;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void delete(String id) {
        if (!StringUtils.hasText(id)) {
            throw new BusinessException("F0000", "文件夹ID不能为空");
        }
        
        FileFolder folder = this.getById(id);
        if (folder == null || folder.getDeletedAt() != null) {
            throw new BusinessException("F0002", "文件夹不存在: " + id);
        }
        
        // 检查是否有子文件夹
        LambdaQueryWrapper<FileFolder> query = new LambdaQueryWrapper<>();
        query.eq(FileFolder::getParentId, id)
             .isNull(FileFolder::getDeletedAt);
        
        long childCount = this.count(query);
        if (childCount > 0) {
            throw new BusinessException("F0001", "文件夹下存在子文件夹，无法删除");
        }
        
        // 软删除
        folder.setDeletedAt(LocalDateTime.now());
        this.updateById(folder);
        
        log.info("删除文件夹成功: folderId={}, name={}", id, folder.getName());
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public FileFolder move(String id, String newParentId) {
        if (!StringUtils.hasText(id)) {
            throw new BusinessException("F0000", "文件夹ID不能为空");
        }
        
        FileFolder folder = this.getById(id);
        if (folder == null || folder.getDeletedAt() != null) {
            throw new BusinessException("F0002", "文件夹不存在: " + id);
        }
        
        // 检查不能移动到自己的子目录
        if (StringUtils.hasText(newParentId)) {
            if (isDescendant(folder.getTenantId(), newParentId, id)) {
                throw new BusinessException("F0001", "不能将文件夹移动到自己的子目录");
            }
        }
        
        folder.setParentId(newParentId);
        String newFullPath = generateFullPath(folder.getTenantId(), newParentId, folder.getName());
        folder.setFullPath(newFullPath);
        
        this.updateById(folder);
        
        log.info("移动文件夹成功: folderId={}, newParentId={}", id, newParentId);
        return folder;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public FileFolder rename(String id, String newName) {
        if (!StringUtils.hasText(id)) {
            throw new BusinessException("F0000", "文件夹ID不能为空");
        }
        if (!StringUtils.hasText(newName)) {
            throw new BusinessException("F0000", "新文件夹名称不能为空");
        }
        
        FileFolder folder = this.getById(id);
        if (folder == null || folder.getDeletedAt() != null) {
            throw new BusinessException("F0002", "文件夹不存在: " + id);
        }
        
        // 检查同级目录下是否有同名文件夹
        LambdaQueryWrapper<FileFolder> query = new LambdaQueryWrapper<>();
        query.eq(FileFolder::getTenantId, folder.getTenantId())
             .eq(FileFolder::getParentId, folder.getParentId())
             .eq(FileFolder::getName, newName)
             .ne(FileFolder::getId, id)
             .isNull(FileFolder::getDeletedAt);
        
        FileFolder existing = this.getOne(query);
        if (existing != null) {
            throw new BusinessException("F0001", "同级目录下已存在同名文件夹: " + newName);
        }
        
        folder.setName(newName);
        String newFullPath = generateFullPath(folder.getTenantId(), folder.getParentId(), newName);
        folder.setFullPath(newFullPath);
        
        this.updateById(folder);
        
        log.info("重命名文件夹成功: folderId={}, newName={}", id, newName);
        return folder;
    }

    @Override
    public Page<FileFolder> pageQuery(int pageNum, int pageSize, String tenantId, 
                                      String parentId, String keyword) {
        if (pageNum < 1) {
            pageNum = 1;
        }
        if (pageSize < 1 || pageSize > 100) {
            pageSize = 20;
        }
        
        Page<FileFolder> page = new Page<>(pageNum, pageSize);
        LambdaQueryWrapper<FileFolder> query = new LambdaQueryWrapper<>();
        
        if (StringUtils.hasText(tenantId)) {
            query.eq(FileFolder::getTenantId, tenantId);
        }
        if (StringUtils.hasText(parentId)) {
            query.eq(FileFolder::getParentId, parentId);
        } else {
            query.isNull(FileFolder::getParentId);
        }
        if (StringUtils.hasText(keyword)) {
            query.like(FileFolder::getName, keyword);
        }
        
        query.isNull(FileFolder::getDeletedAt);
        query.orderByAsc(FileFolder::getCreatedAt);
        
        return this.page(page, query);
    }

    @Override
    public List<FileFolder> listChildren(String tenantId, String parentId) {
        LambdaQueryWrapper<FileFolder> query = new LambdaQueryWrapper<>();
        query.eq(FileFolder::getTenantId, tenantId)
             .eq(FileFolder::getParentId, parentId)
             .isNull(FileFolder::getDeletedAt)
             .orderByAsc(FileFolder::getCreatedAt);
        
        return this.list(query);
    }

    @Override
    public List<FileFolder> listTree(String tenantId, String parentId) {
        List<FileFolder> children = listChildren(tenantId, parentId);
        
        // 递归加载子节点
        return children.stream()
                .map(folder -> {
                    List<FileFolder> subFolders = listTree(tenantId, folder.getId());
                    // 这里可以设置子节点，如果需要的话
                    return folder;
                })
                .collect(Collectors.toList());
    }

    /**
     * 生成完整路径
     */
    private String generateFullPath(String tenantId, String parentId, String name) {
        if (!StringUtils.hasText(parentId)) {
            return "/" + name;
        }
        
        FileFolder parent = this.getById(parentId);
        if (parent == null) {
            return "/" + name;
        }
        
        String parentPath = parent.getFullPath();
        if (parentPath.endsWith("/")) {
            return parentPath + name;
        } else {
            return parentPath + "/" + name;
        }
    }

    /**
     * 检查是否是后代节点
     */
    private boolean isDescendant(String tenantId, String ancestorId, String descendantId) {
        if (ancestorId == null || descendantId == null) {
            return false;
        }
        if (ancestorId.equals(descendantId)) {
            return true;
        }
        
        FileFolder folder = this.getById(descendantId);
        if (folder == null || folder.getParentId() == null) {
            return false;
        }
        
        return isDescendant(tenantId, ancestorId, folder.getParentId());
    }
}

